import logging
from time import sleep

import allure
from appium.webdriver.common.appiumby import AppiumBy
from appium.webdriver.webdriver import WebDriver
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait


class BasePage:
    # 获取传入的driver赋值给self.driver
    def __init__(self, driver: WebDriver = None):
        self.driver = driver

    '''
    封装定位方法
    通过元组的方式传入元素定位，例如：
    _shutter_locator = (By.XPATH, "//*[@resource-id='com.pi.pilot.camera:id/iv_shutter']")
    _shutter_locator = ("xpath", "//*[@resource-id='com.pi.pilot.camera:id/iv_shutter']")
    _shutter_locator = (By.ID, "com.pi.pilot.camera:id/iv_shutter")
    '''
    _center_coordinate = [(240, 400)]
    _left_coordinate = [(15, 400)]
    _right_coordinate = [(465, 400)]
    _up_coordinate = [(240, 50)]
    _down_coordinate = [(240, 780)]

    def find(self, by, locator=None):
        if locator is None:
            logging.info(f"查找元素'{by}'")
            return self.driver.find_element(*by)  # 以元组传入元素并解包
        else:
            logging.info(f"查找元素'{by},{locator}'")
            return self.driver.find_element(by, locator)

    def find_element_text(self, by_locator):
        logging.info("查询元素的文本")
        return self.find(by_locator).get_attribute("text")

    # 封装定位和点击方法
    @allure.step("查找并点击元素")
    def find_and_click(self, by_locator):
        logging.info(f"即将查找和点击'{by_locator}'")
        return self.find(by_locator).click()

    @allure.step("点击坐标")
    def find_coordinate_and_click(self, coordinate):
        # 【【【coordinate需要是列表包含坐标元组】】】
        logging.info(f"点击坐标'{coordinate}'")
        return self.driver.tap(coordinate)

    # 封装定位和输入文本方法
    @allure.step("查找元素并输入文本")
    def find_and_send_text(self, by_locator, text):
        logging.info(f"查找元素'{by_locator}'并输入文本'{text}'")
        return self.find(by_locator).send_keys(text)

    # 查找多个元素并返回列表
    @allure.step("查找多个元素")
    def finds(self, by, locator=None):
        if locator is None:
            logging.info(f"查找多个元素'{by}'")
            return self.driver.find_elements(*by)  # 以元组传入元素并解包
        else:
            logging.info(f"查找多个元素'{by},{locator}'")
            return self.driver.find_elements(by, locator)

    @allure.step("点击中心空白处")
    def click_blank_center(self, times=1):
        self.wait_for_one_second()
        logging.info(f"点击中心空白处'{times}'次")
        for i in range(times):
            self.find_coordinate_and_click(self._center_coordinate)
            self.wait_for_one_second()
        return self

    @allure.step("点击左侧空白处")
    def click_blank_left(self, times=1):
        self.wait_for_one_second()
        logging.info(f"点击左侧空白处'{times}'次")
        for i in range(times):
            self.find_coordinate_and_click(self._left_coordinate)
            self.wait_for_one_second()
        return self

    @allure.step("点击右侧空白处")
    def click_blank_right(self, times=1):
        self.wait_for_one_second()
        logging.info(f"点击右侧空白处'{times}'次")
        for i in range(times):
            self.find_coordinate_and_click(self._right_coordinate)
            self.wait_for_one_second()
        return self

    @allure.step("点击上方空白处")
    def click_blank_up(self, times=1):
        self.wait_for_one_second()
        logging.info(f"点击上方空白处'{times}'次")
        for i in range(times):
            self.find_coordinate_and_click(self._up_coordinate)
            self.wait_for_one_second()
        return self

    @allure.step("点击下方空白处")
    def click_blank_down(self, times=1):
        self.wait_for_one_second()
        logging.info(f"点击下方空白处'{times}'次")
        for i in range(times):
            self.find_coordinate_and_click(self._down_coordinate)
            self.wait_for_one_second()
        return self

    # 滑动页面并找到有特定文本的元素
    @allure.step("上下滑动页面查找文本")
    def swipe_find_text(self, text):
        logging.info(f"上划直到找到文本'{text}'")
        locator = self.driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, 'new UiScrollable(new UiSelector().'
                                                                         'scrollable(true).instance(0)).'
                                                                         f'scrollIntoView(new UiSelector().text("{text}")'
                                                                         '.instance(0));')
        return locator  # 这种方式返回的locator可以直接.click()进行点击

    # 封装滑动页面找到元素并点击的方法
    @allure.step("上下滑动页面查找文本并点击")
    def swipe_find_text_click(self, text):
        logging.info(f"点击查找到的文本'{text}'")
        self.swipe_find_text(text).click()
        self.wait_for_one_second()
        return self

    # 封装获取页面宽高方法
    def get_devices_bounds(self):
        width = self.driver.get_window_rect()["width"]
        height = self.driver.get_window_rect()["height"]
        logging.info(f"获取页面的宽高，宽为'{width}'，高为'{height}'")
        return width, height

    # 封装上滑翻页操作
    def swipe_up(self, times=1):
        width_start = self.get_devices_bounds()[0] * 0.5
        height_start = self.get_devices_bounds()[1] * 0.7
        width_end = self.get_devices_bounds()[0] * 0.5
        height_end = self.get_devices_bounds()[1] * 0.2
        logging.info(f"滑动坐标起点为'{(width_start, height_start)}'，终点为'{width_end, height_end}'")
        for i in range(times):
            self.driver.swipe(width_start, height_start, width_end, height_end, duration=500)
            self.wait_for_one_second(3)
            logging.info("上滑1次")
        # logging.info(f"上滑'{n}'次")
        return self

    # 封装顶部下拉操作
    def open_drop_down_menu(self):
        width_start = self.get_devices_bounds()[0] * 0.5
        height_start = self.get_devices_bounds()[1] * 0.01
        width_end = self.get_devices_bounds()[0] * 0.5
        height_end = self.get_devices_bounds()[1] * 0.8
        logging.info("展开下拉菜单")
        self.driver.swipe(width_start, height_start, width_end, height_end, duration=500)
        self.wait_for_one_second()
        return self

    # 封装返回，相当于手机返回键
    def back(self, times=1):
        self.wait_for_one_second()
        for i in range(times):
            self.driver.back()
            self.wait_for_one_second()
        logging.info(f"返回'{times}'次")
        return self

    # 封装home键
    def home(self):
        logging.info("按home键")
        self.driver.press_keycode(3)
        self.wait_for_one_second(2)
        return self

    # 输出当前页面的元素内容
    def get_current_page_elements(self):
        logging.info("获取当前页面的所有元素")
        current_page = self.driver.page_source
        return current_page

    # 获取toast文字内容
    def get_toast_text(self):
        toast_text = self.find(AppiumBy.XPATH, "//*[@class='android.widget.Toast']").get_attribute("text")
        logging.info(f"toast的内容是'{toast_text}'")
        return toast_text

    # 判断元素是否可以找到
    def is_element_exist(self, by_locator):
        try:
            logging.info(f"尝试查找'{by_locator}'")
            self.find(by_locator)
        except Exception as e:
            logging.info(f"没有找到元素'{by_locator}'")
            logging.info(f"原因是'{e}'")
            return False
        else:
            logging.info(f"找到了元素'{by_locator}'")
            return True

    # 等待元素出现
    def wait_until_element_exists(self, by_locator):
        logging.info(f"等待元素'{by_locator}'出现")
        WebDriverWait(self.driver, 25).until(expected_conditions.visibility_of_element_located(by_locator))
        return self

    # 等待一段时间，单位秒
    @staticmethod
    def wait_for_one_second(second=1):
        logging.info(f"等待{second}秒")
        sleep(second)

    # # 从元素1滑动到元素2【不能正常生效】
    # def scroll_to_element(self, by_locator1, by_locator2):
    #     el1 = self.find(by_locator1)
    #     el2 = self.find(by_locator2)
    #     self.driver.scroll(el1, el2)
    #     logging.info(f"从元素'{by_locator1}'滑动到元素'{by_locator2}'")


